---
title: Recipes
sidebar_position: 1
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

import { ChangingStencilExample } from '../../src/components/examples/ChangingStencilExample';
import { StencilGridExample } from '../../src/components/examples/StencilGridExample';
import { GettingResultExample } from '../../src/components/examples/GettingResultExample';
import { GettingResultManualExample } from '../../src/components/examples/GettingResultManualExample';
import { ResizeResultExample } from '../../src/components/examples/ResizeResultExample';
import { PreviewResultExample } from '../../src/components/examples/PreviewResultExample';
import { LoadImageExample } from '../../src/components/examples/LoadImageExample';
import { UploadExample } from '../../src/components/examples/UploadExample';

# Recipes


## Stencil Tuning

### Change the stencil

There are only two default stencil components now, `RectangleStencil` (default) and `CircleStencil`, but you can easily create your own stencil himself.

To specify stencil component you should pass it to `stencilComponent` prop. For globally registered component just pass their name:
```jsx
<Cropper
	stencilComponent={CircleStencil}
/>
```

<ChangingStencilExample/>

```jsx
import React, { useState } from 'react';
import { CircleStencil, Cropper } from 'react-advanced-cropper';

export const Example = () => {
	const [image] = useState(
		'https://images.unsplash.com/photo-1599140849279-1014532882fe?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1300&q=80',
	);

	return (
		<Cropper
			src={image}
			stencilComponent={CircleStencil}
		/>
	)
};
```

### Pass props to the stencil

To pass any props to the stencil pass them as object to `stencilProps` prop.

For example, that's how you can set aspect ratio:

```jsx
<Cropper
	stencilProps={{
		aspectRatio: 6/9,
		movable: false,
		resizable: false
	}}
/>
```

The list of available props varies from one stencil component to another. The props of the default stencils are available in the documentation ([RectangleStencil](/docs/components/RectangleStencil), [CircleStencil](/docs/components/CircleStencil))

### Set the aspect ratio

This library supports setting either aspect ratio value or aspect ratio range (i.e. minimum and maximums aspect ratio values).

Generally speaking, aspect ratio is the property of the stencil, not the cropper, so the possibility to set aspect ratio
entirely depends of used stencil. For example, `CircleStencil` aspect ratio can't be customized, it's always a circle, at the same time
`RectangleStencil` has not any restrictions on aspect ratios.

The examples below are written for `RectangleStencil`.

#### Fixed aspect ratio
```jsx
<Cropper
	stencilProps={{
		aspectRatio: 1/1,
	}}
/>
```

#### Aspect ratio range
```jsx
<Cropper
	stencilProps={{
		aspectRatio: {
			minimum: 16/8,
			maximum: 4/8
		}
	}}
/>
```

### Add the grid

You can enable the stencil grid for the default stencils to facilitate
the selecting of the cropped area.

```jsx
<Cropper
	stencilProps={{
		grid: true
	}}
/>
```

<StencilGridExample/>

## Getting the result

### First approach

To get the current stencil coordinates and canvas with cropped image
you can call the cropper methods `getCoordinates` and `getCanvas` respectively.

Click at the button **Crop Image** below to see this method in action
<GettingResultManualExample/>

```tsx
import React, { useState, useRef } from 'react';
import { Cropper, CropperRef, Coordinates } from 'react-advanced-cropper';

export const Example = () => {
	const cropperRef = useRef<CropperRef>(null);

	const [coordinates, setCoordinates] = useState<Coordinates | null>(null);
	const [image, setImage] = useState<string>();

	const [src, setSrc] = useState(
		'https://images.unsplash.com/photo-1599140849279-1014532882fe?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1300&q=80',
	);

	const onCrop = () => {
		if (cropperRef.current) {
			setCoordinates(cropperRef.current.getCoordinates());
			// You are able to do different manipulations at a canvas
			// but there we just get a cropped image, that can be used
			// as src for <img/> to preview result
			setImage(cropperRef.current.getCanvas()?.toDataURL());
		}
	};

	return (
		<Cropper
			ref={cropperRef}
			src={src}
		/>;
	)
};
```

### Second approach

Also there is alternative to get the cropper result. You can get the coordinates of stencil and canvas with cropped image by processing one of
[numerous callbacks](/docs/components/cropper/#callbacks).

The example below shows processing the `onChange` event.


:::tip
Though, be careful. Getting the canvas result in `onChange` callback can heavily affect the performance, it's better to use this approach to
get the coordinates, transitions and other plain properties. If you still need to get the canvas result in this callback, use [debounce](https://www.npmjs.com/package/debounce).
:::

<GettingResultExample/>

```jsx
import { Cropper, CropperRef } from 'react-advanced-cropper';

export const Example = () => {
	const [coordinates, setCoordinates] = useState<Coordinates | null>(null);
	const [image, setImage] = useState<string>();

	const [src] = useState(
		'https://images.unsplash.com/photo-1599140849279-1014532882fe?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1300&q=80',
	);

	const onChange = (cropper: CropperRef) => {
		setCoordinates(cropper.getCoordinates());
		setImage(cropper.getCanvas()?.toDataURL());
	};

	return (
		<Cropper
			src={src}
			onChange={onChange}
		/>;
	)
};
```


## Resize the result

If you use coordinates only, the result should be scaled on server-side, but if you use canvas you may prefer to resize the result on client-side.

The most simplest way to do it is pass the restrictions for the result size in `getCanvas` method options.

```jsx
const canvas = cropper.getCanvas({
		minHeight: 0,
		minWidth: 0,
		maxHeight: 2048,
		maxWidth: 2048,
})
```

If you need to set the specific height and width use `height` and `width` attributes.
But you should note that canvas will have the same aspect ratio as the stencil, so the result size may
be different than one that you have set.
```jsx
const canvas = cropper.getCanvas({
		height: 256,
		width: 256,
})
```

<ResizeResultExample/>

It uses default canvas image scaling procedure under the hood. If the result doesn't suit you, try to use the external libraries
to resize image ([pica](https://github.com/nodeca/pica), [downscale](https://github.com/ytiurin/downscale) and etc.)

## Preview the result

To implement real-time preview of cropping result you can use [`CropperPreview`](/docs/components/CropperPreview) component.

<PreviewResultExample/>

<br/>

There are currently exists two competing approaches to use `<CropperPreview/>`. Which one will
remain still not decided, so feel free to use any of them.


<Tabs>
<TabItem value="update" label="Update" default>

:::info
This approach is available starting from `0.20.0` version
:::

```tsx
import React, { useRef, useState } from 'react';
import { CropperRef, CropperPreviewRef, Cropper } from 'react-advanced-cropper';

export const Example = () => {
	const previewRef = useRef<CropperPreviewRef>(null);
	const cropperRef = useRef<CropperRef>(null);
	const [src, setSrc] = useState(
		'https://images.unsplash.com/photo-1623432532623-f8f1347d954c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=387&q=80',
	);

	const onUpdate = (cropper: CropperRef) => {
		previewRef.current?.update(cropper);
	};

	return (
		<div>
			<Cropper
				className="cropper"
				stencilProps={{ aspectRatio: 1 }}
				src={src}
				onUpdate={onUpdate}
			/>
			<CropperPreview
				ref={previewRef}
				className="preview"
			/>
		</div>
	);
};
```

</TabItem>
<TabItem value="state" label="Stateful" >

```tsx
import React, { useRef, useState } from 'react';
import {
	Cropper,
	CropperPreview,
	CropperState,
	CropperImage,
	CropperTransitions,
} from 'react-advanced-cropper';

interface PreviewState {
	state: CropperState | null;
	image: CropperImage | null;
	transitions: CropperTransitions | null;
	loading?: false;
	loaded?: false;
}

export const Example = () => {
	const [previewState, setPreviewState] = useState<PreviewState>({
		state: null,
		image: null,
		transitions: null
	});

	const [src, setSrc] = useState(
		'https://images.unsplash.com/photo-1623432532623-f8f1347d954c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=387&q=80',
	);

	const onUpdate = () => {
		setPreviewState({
			state: cropper.getState(),
			image: cropper.getImage(),
			transitions: cropper.getTransitions(),
			loaded: cropper.isLoaded(),
			loading: cropper.isLoading(),
		});
	};

	return (
		<div>
			<Cropper
				ref={cropperRef}
				className="cropper"
				stencilProps={{ aspectRatio: 1 }}
				src={src}
				onUpdate={onUpdate}
			/>
			<CropperPreview
				ref={previewRef}
				className="preview"
				{...previewState}
			/>
		</div>
	);
};
```

</TabItem>
<TabItem value="two-references" label="Two References">

:::warning
This approach is deprecated since 0.20.0
:::

```jsx
import React, { useRef, useState } from 'react';
import { CropperRef, CropperPreviewRef, Cropper } from 'react-advanced-cropper';

export const Example = () => {
	const previewRef = useRef<CropperPreviewRef>(null);
	const cropperRef = useRef<CropperRef>(null);

	const [src, setSrc] = useState(
		'https://images.unsplash.com/photo-1623432532623-f8f1347d954c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=387&q=80',
	);

	const onUpdate = () => {
		previewRef.current?.refresh();
	};

	return (
		<div>
			<Cropper
				ref={cropperRef}
				className="cropper"
				stencilProps={{ aspectRatio: 1 }}
				src={src}
				onUpdate={onUpdate}
			/>
			<CropperPreview
				ref={previewRef}
				cropper={cropperRef}
				className="preview"
			/>
		</div>
	);
};
```

</TabItem>
</Tabs>


As an alternative you can  add the preview component inside the cropper wrapper, just like the slider in [this tutorial](/docs/tutorials/absolute-zoom/).
It can even improve the performance slightly.

## Load image from a disc

The image loading doesn't depend at this library and can be completed by a numerous ways. There will be considered only one of them.

That's what you will get:
<LoadImageExample/>

:::warning Warning!
[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) is used in the example below. Ensure that browsers that you support can fully handle it or use the corresponding polyfill.
:::
<Tabs>

<TabItem value="simple" label="Simple Example" default>

```js
import React, { ChangeEvent, useState, useRef, useEffect } from 'react';
import { CropperRef, Cropper } from 'react-advanced-cropper';

interface Image {
	type?: string;
	src: string;
}

export const UploadExample = () => {
	const inputRef = useRef<HTMLInputElement>(null);

	const [image, setImage] = useState<Image | null>(null);

	const onUpload = () => {
		if (inputRef.current) {
			inputRef.current.click();
		}
	};

	const onLoadImage = (event: ChangeEvent<HTMLInputElement>) => {
		// Reference to the DOM input element
		const { files } = event.target;

		// Ensure that you have a file before attempting to read it
		if (files && files[0]) {
			// Create the blob link to the file to optimize performance:
			const blob = URL.createObjectURL(files[0]);

			// Get the image type from the extension. It's the simplest way, though be careful it can lead to an incorrect result:
			setImage({
			   src: blob,
			   type: files[0].type
			})
		}
		// Clear the event target value to give the possibility to upload the same image:
		event.target.value = '';
	};

	useEffect(() => {
		// Revoke the object URL, to allow the garbage collector to destroy the uploaded before file
		return () => {
			if (image && image.src) {
				URL.revokeObjectURL(image.src);
			}
		};
	}, [image]);

	return (
		<div className="upload-example">
			<Cropper className="upload-example__cropper" src={image && image.src} />
			<div className="buttons-wrapper">
				<button className="button" onClick={onUpload}>
					<input ref={inputRef} type="file" accept="image/*" onChange={onLoadImage} />
					Upload image
				</button>
			</div>
		</div>
	);
};
```

</TabItem>

<TabItem value="advanced" label="Advanced Example" default>

:::note Notice!
The function `getMimeType` is imported from from `advanced-cropper`, not from `react-advanced-cropper`. It's the dependency of `react-advanced-cropper`. And it's
preferred way to import such dependencies if you use a bundler (in the future it will be only possible way).
:::

```js
import React, { ChangeEvent, useState, useRef, useEffect } from 'react';
import { CropperRef, Cropper } from 'react-advanced-cropper';
import { getMimeType } from 'advanced-cropper/extensions/mimes';

interface Image {
	type?: string;
	src: string;
}

export const UploadExample = () => {
	const inputRef = useRef<HTMLInputElement>(null);

	const [image, setImage] = useState<Image | null>(null);

	const onUpload = () => {
		if (inputRef.current) {
			inputRef.current.click();
		}
	};

	const onLoadImage = (event: ChangeEvent<HTMLInputElement>) => {
		// Reference to the DOM input element
		const { files } = event.target;

		// Ensure that you have a file before attempting to read it
		if (files && files[0]) {
			// Create the blob link to the file to optimize performance:
			const blob = URL.createObjectURL(files[0]);

			// Remember the fallback type:
			const typeFallback = files[0].type;

			// Create a new FileReader to read this image binary data
			const reader = new FileReader();

			// Define a callback function to run, when FileReader finishes its job
			reader.onload = (e) => {
				// Note: arrow function used here, so that "this.image" refers to the image of Vue component
				setImage({
					// Read image as base64 and set it as src:
					src: blob,
					// Determine the image type to preserve it during the extracting the image from canvas:
					type: getMimeType(e.target?.result, typeFallback),
				});
			};
			// Start the reader job - read file as a data url (base64 format) and get the real file type
			reader.readAsArrayBuffer(files[0]);
		}
		// Clear the event target value to give the possibility to upload the same image:
		event.target.value = '';
	};

	useEffect(() => {
		// Revoke the object URL, to allow the garbage collector to destroy the uploaded before file
		return () => {
			if (image && image.src) {
				URL.revokeObjectURL(image.src);
			}
		};
	}, [image]);

	return (
		<div className="upload-example">
			<Cropper className="upload-example__cropper" src={image && image.src} />
			<div className="buttons-wrapper">
				<button className="button" onClick={onUpload}>
					<input ref={inputRef} type="file" accept="image/*" onChange={onLoadImage} />
					Upload image
				</button>
			</div>
		</div>
	);
};
```

</TabItem>

</Tabs>


## Upload image to a server

The preferred method to upload image to the server is using [a blob](https://developer.mozilla.org/ru/docs/Web/API/HTMLCanvasElement/toBlob) (for IE-11 you should use polyfill).
The detailed explanation why you shouldn't use the data-url you can read [in the great answer](https://stackoverflow.com/questions/59020799/which-function-should-i-use-todataurl-or-toblob/59025746#59025746) on Stackoverflow.

There are different approaches to implement image uploading because it depends on your backend. The one of them is presented below.

<UploadExample></UploadExample>

:::tip
*Look the network section in your developer tools to examine the sent request.*
:::

```tsx
import React, { useState, useRef } from 'react';
import { CropperRef, Cropper } from 'react-advanced-cropper';

export const UploadExample = () => {
	const cropperRef = useRef<CropperRef>(null);

	const [image] = useState(
		'https://images.unsplash.com/photo-1604335079441-274c03ad99a1?ixlib=rb-1.2.1&auto=format&fit=crop&w=1024&q=80',
	);

	const onUpload = () => {
		const canvas = cropperRef.current?.getCanvas();
		if (canvas) {
			const form = new FormData();
			canvas.toBlob((blob) => {
				if (blob) {
					form.append('file', blob);
					fetch('http://example.com/upload/', {
						method: 'POST',
						body: form,
					});
				}
			}, 'image/jpeg');
		}
	};

	return (
		<Cropper
			ref={cropperRef}
			src={image}
		/>
	);
};

```
